package com.heima.media.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.dto.ResponseResult;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.minio.MinIOService;
import com.heima.common.util.SensitiveWordUtil;
import com.heima.media.dto.ArticleDto;
import com.heima.media.dto.ContentDto;
import com.heima.media.dto.ImageDto;
import com.heima.media.entity.WmChannel;
import com.heima.media.entity.WmNews;
import com.heima.media.entity.WmSensitive;
import com.heima.media.entity.WmUser;
import com.heima.media.fegin.ArticleFeign;
import com.heima.media.service.*;
import org.apache.commons.io.IOUtils;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

@Service
public class AuditServiceImpl implements IAuditSrevice {
//    自动审核
    @Async
    @Override
    public void audit(WmNews wmNews) {

        System.out.println(Thread.currentThread().getName() + " 开始执行自动审核服务...");
//        4人工审核通过的 或者8待提交的
        if(wmNews.getStatus()==4||wmNews.getStatus()==8){
//            发布时间没到的
            if(System.currentTimeMillis()<=wmNews.getPublishTime().getTime()){
                sendDelayMessage(wmNews);

            }else{

                saveArticle(wmNews);
            }
            return;
        }









//        审核嘛当然先看新闻的状态了如果是1的话就是daishenhe
        if(wmNews.getStatus()==1){
//            如果是待审核就先获得他的文章图片和文章
            Map<String,Object> map=getTextAndImageByContent(wmNews.getContent());
//            获得了具体数据就应该从中提取文字和图片了‘
//            先提取文字
            String text = (String) map.get("text");
//            进行本地敏感词库的检索
           Boolean sensResult=checkSens(wmNews,text);
           if (!sensResult)return;
//            先审核文字
            Boolean textResult=checkText(wmNews,text);
//            获得了一个状态 如果不通过就结束方法返回
            if(!textResult) return;
//            在获得图片
            List<String> images = (List<String>) map.get("image");
//            图片是一个数组我们想添加的应该是一个个的字符串
//            从wmNews的封面图片属性获得图片的数据
            List<ImageDto> wmNewsList = JSON.parseArray(wmNews.getImages(), ImageDto.class);
//遍历这个数组看看图片里的url包含封面图骗的吗
            for (ImageDto image :wmNewsList
                 ) {
//                判断包不包含
                if(!wmNewsList.contains(image.getUrl())){
//                    不包含就添加
                    images.add(image.getUrl());

                }


            }
//            开始审核图片
          Boolean imageResult=checkImage(wmNews,images);
            if(!imageResult)return;
            if(System.currentTimeMillis()<=wmNews.getPublishTime().getTime()){
                sendDelayMessage(wmNews);
            }else {
//                添加文章
                saveArticle(wmNews);

            }




        }

    }
    @Autowired
    private RedissonClient redissonClient;
//延时发布文章
    private void sendDelayMessage(WmNews wmNews) {
//        改为待发布
        wmNews.setStatus(8);
        newsService.updateById(wmNews);
//        发送延时消息  获得一个阻塞队列
        RBlockingQueue<Object> blockingQueue = redissonClient.getBlockingQueue("article-publish");
//        获得一个延时队列
        RDelayedQueue<Object> delayedQueue = redissonClient.getDelayedQueue(blockingQueue);
//        发布时间与本地时间的时间差
        long time = wmNews.getPublishTime().getTime() - System.currentTimeMillis();
        delayedQueue.offer(wmNews,time, TimeUnit.SECONDS);


    }

    //    进行本地敏感词的检索
@Autowired
private IWmSensitiveService wmSensitiveService;

    private Boolean checkSens(WmNews wmNews, String text) {
//        如果敏感词汇的map集合要是空的 就开始查询数据库查询
        if(SensitiveWordUtil.dictionaryMap.size()==0){
            LambdaQueryWrapper<WmSensitive> query=new LambdaQueryWrapper<>();
            query.select(WmSensitive::getSensitives);
            List<String> list = wmSensitiveService.listObjs(query, o -> o.toString());
            SensitiveWordUtil.initMap(list);

        }
//        敏感词集合初始化完了 ，就开始校验了
        Map<String, Integer> map = SensitiveWordUtil.matchWords(text + wmNews.getTitle() + wmNews.getLabels());
//        如果看看敏感词查询的频率 如果有不通过
        if(map.size()>0){
//            改变状态
            wmNews.setStatus(2);
//            获得所有的敏感词
            Set<String> keySet = map.keySet();
//            将敏感词装化成字符串
            String join = String.join("", keySet);
            wmNews.setReason(join);
            newsService.updateById(wmNews);
            return false;

        }
        return true;
    }

    @Autowired
    private ArticleFeign articleFeign;

    @Autowired
    private IWmUserService userService;

    @Autowired
    private IWmChannelService channelService;

    //保存文章
    private void saveArticle(WmNews wmNews) {
        ArticleDto dto=new ArticleDto();
        dto.setTitle(wmNews.getTitle());
        WmUser wmUser = userService.getById(wmNews.getUserId());
        dto.setAuthorId(wmUser.getApAuthorId());
        dto.setAuthorName(wmUser.getName());
        dto.setChannelId(wmNews.getChannelId());
        WmChannel wmChannel = channelService.getById(dto.getChannelId());
        dto.setChannelName(wmChannel.getName());
        dto.setLabels(wmNews.getLabels());
        dto.setFlag(0);
//       前端需要的，字符串
        List<ImageDto> imageDtos = JSON.parseArray(wmNews.getImages(), ImageDto.class);
        List<String> images=new ArrayList<>();
        for (ImageDto image:imageDtos
             ) {
            images.add(image.getUrl());

        }
//        将数组装化成字符串
        String join = String.join(",", images);
        dto.setImages(join);
        dto.setContent(wmNews.getContent());
        ResponseResult<Long> responseResult = articleFeign.saveArticle(dto);
        if(responseResult.getCode().equals(AppHttpCodeEnum.SUCCESS.getCode())){
            Long resultData = responseResult.getData();
            if(resultData!=null){
                wmNews.setArticleId(resultData);
                wmNews.setStatus(9);
                newsService.updateById(wmNews);
            }
        };


    }


    @Autowired
   private GreenTextScan textScan;
    @Autowired
    private GreenImageScan imageScan;
    @Autowired
    private IWmNewsService newsService;
    @Autowired
    private MinIOService minIOService;




    //这个类似于文本的审核
    private Boolean checkImage(WmNews wmNews, List<String> images) {
//        同下立个flage
        Boolean flage=false;
//        是个集合先判断各大小吧
        if(images.size()==0){
            return true;
        }
//        先创建一个字节的数组 因为minio 需要先下载然后在审核
        List<byte[]> imageList=new ArrayList<>();
        for (String image:images
             ) {

            try {
                //           调用封装的方法获得一个六
                InputStream inputStream = minIOService.download(image);
                byte[] bytes = IOUtils.toByteArray(inputStream);
                imageList.add(bytes);

            } catch (IOException e) {
                e.printStackTrace();
            }


        }
        try {
//        开始审核
            Map map = imageScan.imageScan(imageList);
            String suggestion = (String) map.get("suggestion");
            switch (suggestion){
                case "pass":
                    flage=true;
                    break;
                case "block":
                    wmNews.setStatus(2);
                    wmNews.setReason("阿里云图片审核不成功"+map.get("label"));
                    newsService.updateById(wmNews);
                    break;
                case "review":
                    wmNews.setStatus(3);
                    newsService.updateById(wmNews);
                    break;

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flage;


    }


//这个方法是调用ali的第三方接口对文章的文字进行审核

    private Boolean checkText(WmNews wmNews, String text) {
//        这个简单就是低矮哦用一下接口对返回值进行状态的比对修改文章状态
//        先立一个false的标志
        Boolean flage=false;
//        需要审查得有标签和文章标题 和文章主ti
        text=wmNews.getLabels()+wmNews.getTitle()+text;
        try {
//            调用ali审查的接口
            Map map = textScan.greenTextScan(text);
//            获得状态
            String suggestion = (String) map.get("suggestion");
//            对返回的状态进行分类判断
            switch (suggestion){
                case "pass":
//                    审合通过
                    flage=true;
                    break;
                case  "block":

//                  审核不通过
//                    修改文章的状态2
                    wmNews.setStatus(2);
                    wmNews.setReason("阿里云文本审核失败"+map.get("label"));
                    newsService.updateById(wmNews);
                    break;
                case "review":
//                    这个是需要人工审核
//                    状态改为3
                    wmNews.setStatus(3);
                    newsService.updateById(wmNews);
                    break;

            }

        } catch (Exception e) {
            e.printStackTrace();
        }

return flage;
    }
//    这个方法是根据前端传的数据获得图片和文字

    private Map<String, Object> getTextAndImageByContent(String content) {
//        这个是接返回数据的
        Map<String,Object> map=new HashMap<>();
//        这个是接返回文字的
        StringBuilder stringBuilder=new StringBuilder();
//        这个是接返回的图片的
        List<String> images=new ArrayList<>();
//        然后将传过来的数据转化成ContentDto对象
        List<ContentDto> imageDtoList = JSON.parseArray(content, ContentDto.class);
        for (ContentDto contenDto:imageDtoList
             ) {
//            开始根据类型分类
            if(contenDto.getType().equals("text")){
//                文字的
                stringBuilder.append(contenDto.getValue());
            }else {
//                图片的
                if(!StringUtils.isEmpty(contenDto.getValue())){
                    images.add(contenDto.getValue());
                }
            }

        }
        map.put("text",stringBuilder.toString());
        map.put("image",images);
        return map;

    }
}
